﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NumericalCalculations
{
    public class DoubleComplex
    {
        
        private double c;
        private double d;
        public static readonly DoubleComplex I;
        public static readonly DoubleComplex Zero;
        public static readonly DoubleComplex One;
        public static readonly DoubleComplex NaN;
        public static readonly DoubleComplex Infinity;

        private static bool a(double A_0)
        {
            return (BitConverter.DoubleToInt64Bits(A_0) == -9223372036854775808L);
        }



        #region Properti

        //properti za realaan deo
        public double Re
        {
            get
            {
                return this.c;
            }

            set
            {
                this.c = value;
            }
        }

        //properti za imaginaran deo
        public double Im
        {
            get
            {
                return this.d;
            }

            set
            {
                this.d = value;
            }
        }


        public bool IsZero
        {
            get
            {
                return ((this.c == 0.0) && (this.d == 0.0));
            }
        }
        public bool IsReal
        {
            get
            {
                return (this.d == 0.0);
            }
        }
        public bool IsImaginary
        {
            get
            {
                return (this.c == 0.0);
            }
        }


        public static bool IsNaN(DoubleComplex z)
        {
            if (!Elementary.IsNaN(z.c))
            {
                return Elementary.IsNaN(z.d);
            }
            return true;
        }

        public static bool IsInfinity(DoubleComplex z)
        {
            if (!double.IsInfinity(z.c))
            {
                return double.IsInfinity(z.d);
            }
            return true;
        }

        public double Argument
        {
            get
            {
                return Math.Atan2(this.d, this.c);
            }
        }


        public double Modulus
        {
            get
            {
                return Elementary.Hypot(this.c, this.d);
            }
        }
        public double ModulusSquared
        {
            get
            {
                return ((this.c * this.c) + (this.d * this.d));
            }
        }


        #endregion

        #region Konstruktori
        //konstruktori
        public DoubleComplex(double realPart, double imaginaryPart)
        {
            this.c = realPart;
            this.d = imaginaryPart;
        }

        public DoubleComplex(double realPart)
        {
            this.c = realPart;
            this.d = 0.0;
        }

        //kreira cisto imaginarni broj(realni deo je 0)
        public static DoubleComplex Imaginary(double imaginaryPart)
        {
            return new DoubleComplex(0.0, imaginaryPart);
        }

        //kreira broj od modula i argumenta
        public static DoubleComplex FromPolar(double modulus, double argument)
        {
            return (modulus * ExpI(argument));
        }
        #endregion

        #region Operatori
 

        //operatori

        public static implicit operator DoubleComplex(double a)
        {
            return new DoubleComplex(a);
        }


        public static explicit operator double(DoubleComplex z)
        {
            return z.c;
        }



         

        public static DoubleComplex operator +(DoubleComplex z)
        {
            return z;
        }

        
        
        public static DoubleComplex operator -(DoubleComplex z)
        {
            return new DoubleComplex(-z.c, -z.d);
        }

       

        public static DoubleComplex operator ++(DoubleComplex z)
        {
            return new DoubleComplex(++z.c, z.d);
        }

       
        public static DoubleComplex operator --(DoubleComplex z)
        {
            return new DoubleComplex(--z.c, z.d);
        }

       

        public static DoubleComplex operator +(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex(z1.c + z2.c, z1.d + z2.d);
        }

        public static DoubleComplex operator +(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c + a, z.d);
        }

        public static DoubleComplex operator +(double a, DoubleComplex z)
        {
            return new DoubleComplex(z.c + a, z.d);
        }

        public static DoubleComplex operator -(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex(z1.c - z2.c, z1.d - z2.d);
        }

        public static DoubleComplex operator -(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c - a, z.d);
        }

        public static DoubleComplex operator -(double a, DoubleComplex z)
        {
            return new DoubleComplex(a- z.c , -z.d);
        }

        public static DoubleComplex operator *(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex((z1.c * z2.c) - (z1.d * z2.d), (z1.c * z2.d) + (z1.d * z2.c));
        }

        public static DoubleComplex operator *(double a, DoubleComplex z)
        {
            return new DoubleComplex(z.c * a, z.d * a);
        }

        public static DoubleComplex operator *(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c * a, z.d * a);
        }

        public static DoubleComplex operator /(DoubleComplex z1, DoubleComplex z2)
        {
            double d;
            double c;
            double num3;
            double num4;
            double num8;
            double num9;
            if (z2.d == 0.0)
            {
                return (z1 / z2.Re);
            }
            bool flag = Math.Abs(z2.d) >= Math.Abs(z2.c);
            if (flag)
            {
                d = z1.d;
                c = z1.c;
                num3 = z2.d;
                num4 = z2.c;
            }
            else
            {
                d = z1.c;
                c = z1.d;
                num3 = z2.c;
                num4 = z2.d;
            }
            double num5 = 1.0 / num3;
            double num6 = 1.0 / (num3 + (num4 * (num4 * num5)));
            if (Math.Abs(num4) > Math.Abs(num5))
            {
                double num7 = num4;
                num4 = num5;
                num5 = num7;
            }
            if (Math.Abs(c) >= Math.Abs(num5))
            {
                num8 = num5 * (c * num4);
            }
            else if (Math.Abs(c) >= Math.Abs(num4))
            {
                num8 = c * (num5 * num4);
            }
            else
            {
                num8 = num4 * (num5 * c);
            }
            num8 = num6 * (d + num8);
            if (Math.Abs(d) >= Math.Abs(num5))
            {
                num9 = num5 * (d * num4);
            }
            else if (Math.Abs(d) >= Math.Abs(num4))
            {
                num9 = d * (num5 * num4);
            }
            else
            {
                num9 = num4 * (num5 * d);
            }
            num9 = num6 * (c - num9);
            if (flag)
            {
                num9 = -num9;
            }
            return new DoubleComplex(num8, num9);
        }

        public static DoubleComplex operator /(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c / a, z.d / a);
        }

        public static DoubleComplex operator /(double a, DoubleComplex z)
        {
            double modulusSquared = z.ModulusSquared;
            if (modulusSquared == 0.0)
            {
                if (a == 0.0)
                {
                    return NaN;
                }
                return Infinity;
            }
            double num2 = a / modulusSquared;
            return new DoubleComplex(num2 * z.c, -num2 * z.d);
        }


        #endregion

        #region Funcije koje odgovaraju operatorima

        //funkcije koje odgovaraju operatorima
        public static DoubleComplex Negate(DoubleComplex z)
        {
            return new DoubleComplex(-z.c, -z.d);
        }

        public static DoubleComplex Plus(DoubleComplex z)
        {
            return z;
        }

        public static DoubleComplex Conjugate(DoubleComplex z)
        {
            return new DoubleComplex(z.c, -z.d);
        }

        public static DoubleComplex Decrement(DoubleComplex z)
        {
            return new DoubleComplex(--z.c, z.d);
        }

        public static DoubleComplex Increment(DoubleComplex z)
        {
            return new DoubleComplex(++z.c, z.d);
        }

        public static DoubleComplex Add(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex(z1.c + z2.c, z1.d + z2.d);
        }

        public static DoubleComplex Add(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c + a, z.d);
        }

        public static DoubleComplex Add(double a, DoubleComplex z)
        {
            return new DoubleComplex(z.c + a, z.d);
        }

        public static DoubleComplex Subtract(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex(z1.c - z2.c, z1.d - z2.d);
        }

        public static DoubleComplex Subtract(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c - a, z.d);
        }

        public static DoubleComplex Subtract(double a, DoubleComplex z)
        {
            return new DoubleComplex(a - z.c, -z.d);
        }

        public static DoubleComplex Multiply(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex((z1.c * z2.c) - (z1.d * z2.d), (z1.c * z2.d) + (z1.d * z2.c));
        }

        public static DoubleComplex Multiply(double a, DoubleComplex z)
        {
            return new DoubleComplex(z.c * a, z.d * a);
        }

        public static DoubleComplex Multiply(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c * a, z.d * a);
        }

        public static DoubleComplex Divide(DoubleComplex z1, DoubleComplex z2)
        {
            double d;
            double c;
            double num3;
            double num4;
            double num8;
            double num9;
            if (z2.d == 0.0)
            {
                return (z1 / z2.Re);
            }
            bool flag = Math.Abs(z2.d) >= Math.Abs(z2.c);
            if (flag)
            {
                d = z1.d;
                c = z1.c;
                num3 = z2.d;
                num4 = z2.c;
            }
            else
            {
                d = z1.c;
                c = z1.d;
                num3 = z2.c;
                num4 = z2.d;
            }
            double num5 = 1.0 / num3;
            double num6 = 1.0 / (num3 + (num4 * (num4 * num5)));
            if (Math.Abs(num4) > Math.Abs(num5))
            {
                double num7 = num4;
                num4 = num5;
                num5 = num7;
            }
            if (Math.Abs(c) >= Math.Abs(num5))
            {
                num8 = num5 * (c * num4);
            }
            else if (Math.Abs(c) >= Math.Abs(num4))
            {
                num8 = c * (num5 * num4);
            }
            else
            {
                num8 = num4 * (num5 * c);
            }
            num8 = num6 * (d + num8);
            if (Math.Abs(d) >= Math.Abs(num5))
            {
                num9 = num5 * (d * num4);
            }
            else if (Math.Abs(d) >= Math.Abs(num4))
            {
                num9 = d * (num5 * num4);
            }
            else
            {
                num9 = num4 * (num5 * d);
            }
            num9 = num6 * (c - num9);
            if (flag)
            {
                num9 = -num9;
            }
            return new DoubleComplex(num8, num9);
        }

        public static DoubleComplex Divide(DoubleComplex z, double a)
        {
            return new DoubleComplex(z.c / a, z.d / a);
        }

        public static DoubleComplex Divide(double a, DoubleComplex z)
        {
            double modulusSquared = z.ModulusSquared;
            if (modulusSquared == 0.0)
            {
                if (a == 0.0)
                {
                    return NaN;
                }
                return Infinity;
            }
            double num2 = a / modulusSquared;
            return new DoubleComplex(num2 * z.c, -num2 * z.d);
        }

        public static DoubleComplex ConjugateMultiply(DoubleComplex z1, DoubleComplex z2)
        {
            return new DoubleComplex((z1.c * z2.c) + (z1.d * z2.d), (z1.c * z2.d) - (z1.d * z2.c));
        }





        #endregion



        #region Metodi
        //svi ostali metodi

        public DoubleComplex Conjugate()
        {
          return new DoubleComplex(this.c, -this.d);
        }

        public static double Abs(DoubleComplex z)
        {
            return z.Modulus;
        }

        public static double Arg(DoubleComplex z)
        {
            return z.Argument;
        }

        public static DoubleComplex RootOfUnity(int degree, int index)
        {
            if (degree == 0)
            {
                throw new ArgumentOutOfRangeException("degree");
            }
            if (index == 0)
            {
                return One;
            }
            return ExpI(((index % degree) * 6.2831853071795862) / ((double) degree));
        }

        public static DoubleComplex ExpI(double angle)
        {
            int num;
            angle = Elementary.a(angle, out num);
            double realPart = Math.Cos(angle);
            double imaginaryPart = Math.Sin(angle);
            switch (num)
            {
                case 0:
                   return new DoubleComplex(realPart, imaginaryPart);

                case 1:
                    return new DoubleComplex(-imaginaryPart, realPart);

                case 2:
                    return new DoubleComplex(-realPart, -imaginaryPart);

                case 3:
                    return new DoubleComplex(imaginaryPart, -realPart);
             }
             return NaN;
        }

        public static DoubleComplex Exp(DoubleComplex z)
        {
            return (Math.Exp(z.c) * ExpI(z.Im));
        }

        public static DoubleComplex ExpMinus1(DoubleComplex z)
        {
           if (z.ModulusSquared > 1.0)
           {
               return (Exp(z) - One);
           }
            double num = Elementary.ExpMinus1(z.Re);
            double num2 = Math.Sin(0.5 * z.Im);
            num2 = (-2.0 * num2) * num2;
            return new DoubleComplex(((num * num2) + num) + num2, (num + 1.0) * Math.Sin(z.Im));
        }

        public static DoubleComplex Log1PlusX(DoubleComplex z)
        {
            if ((Math.Abs(z.Re) < 0.5) && (Math.Abs(z.Im) < 0.5))
            {
                double num = (2.0 * z.Re) + z.ModulusSquared;
                return new DoubleComplex(Elementary.Log1PlusX(num / (1.0 + Math.Sqrt(num + 1.0))), Math.Atan2(1.0 + z.Re, z.Im));
            }
            return Log(1.0 + z);
        }

        public static DoubleComplex Log(DoubleComplex z)
        {   
            return new DoubleComplex(Math.Log(z.Modulus), z.Argument);
        }

        public static DoubleComplex Log(DoubleComplex z, DoubleComplex newBase)
        {
            DoubleComplex complex = Log(newBase);
            DoubleComplex complex2 = Log(z) / complex;
            DoubleComplex complex3 = new DoubleComplex(0.0, 6.2831853071795862) / complex;
            double num = Math.Round((double) (((complex2.c * complex3.c) + (complex2.d * complex3.d)) / complex3.ModulusSquared));
            return (complex2 - (num * complex3));
        }

        public static DoubleComplex Log10(DoubleComplex z)
        {
            return (Log(z) * 0.43429448190325182);
        }

        public static DoubleComplex Pow(DoubleComplex z1, DoubleComplex z2)
        {
            return Exp(Log(z1) * z2);
        }

        public static DoubleComplex Pow(DoubleComplex z, double a)
        {
            int n = (int) a;
            if (a == n)
            {
                return Pow(z, n);
            }
            if (z.IsReal)
            {
                double re = z.Re;
                if (re >= 0.0)
                {
                    return Math.Pow(re, a);
                }
                return (ExpI((a % 2.0) * 3.1415926535897931) * Math.Pow(-re, a));
            }
            if (!z.IsImaginary)
            {
                return Exp(Log(z) * a);
            }
            double im = z.Im;
            if (im > 0.0)
            {
                return (ExpI(((0.5 * a) % 2.0) * 3.1415926535897931) * Math.Pow(im, a));
            }
            return (ExpI(((1.5 * a) % 2.0) * 3.1415926535897931) * Math.Pow(-im, a));
        }

        public static DoubleComplex Pow(DoubleComplex z, int n)
        {
            if (n == 0)
            {
                return new DoubleComplex(1.0, 0.0);
            }
            if (n == 1)
            {
                return z;
            }
            if (z.IsReal)
            {
                return Elementary.Pow(z.Re, n);
            }
            bool flag = false;
            if (n < 0)
            {
                flag = true;
                n = -n;
            }
            if (z.IsZero)
            {
                if (flag)
                {
                    return Infinity;
                }
                return Zero;
            }
            DoubleComplex complex = z;
            DoubleComplex one = One;
            do
            {
                if ((n & 1) != 0)
                {
                    one *= complex;
                }
                complex *= complex;
                n = n >> 1;
            }
            while (n > 0);
            if (flag)
            {
                return (1.0 / one);
            }
            return one;
        }

        public static DoubleComplex Sqrt(DoubleComplex z)
        {
            double num4;
            if (z.d == 0.0)
            {
                if (z.c > 0.0)
                {
                    return new DoubleComplex(Math.Sqrt(z.c));
                }
                double imaginaryPart = Math.Sqrt(-z.c);
                if (a(z.d))
                {
                    return new DoubleComplex(0.0, -imaginaryPart);
                }
                return new DoubleComplex(0.0, imaginaryPart);
            }
            double num2 = Math.Abs(z.c);
            double num3 = Math.Abs(z.d);
            if (num2 >= num3)
            {
                double num5 = num3 / num2;
                num4 = Math.Sqrt((0.5 * num2) * (1.0 + Math.Sqrt(1.0 + (num5 * num5))));
            }
            else
            {
                double num6 = num2 / num3;
                num4 = Math.Sqrt((0.5 * num3) * (num6 + Math.Sqrt(1.0 + (num6 * num6))));
            }
            if (z.c >= 0.0)
            {
                return new DoubleComplex(num4, z.d / (2.0 * num4));
            }
            if (z.d < 0.0)
            {
                num4 = -num4;
            }
            return new DoubleComplex(z.d / (2.0 * num4), num4);
        }

        public static DoubleComplex Sqrt(double a)
        {
            if (a < 0.0)
            {
                return new DoubleComplex(0.0, Math.Sqrt(-a));
            }
            return new DoubleComplex(Math.Sqrt(a), 0.0);
        }

        public static DoubleComplex Sin(DoubleComplex z)
        {
            if (z.IsReal)
            {
                return new DoubleComplex(Elementary.Sin(z.c));
            }
            return new DoubleComplex(Elementary.Sin(z.c) * Math.Cosh(z.d), Elementary.Cos(z.c) * Math.Sinh(z.d));
        }

        public static DoubleComplex Cos(DoubleComplex z)
        {
            if (z.IsReal)
            {
                return new DoubleComplex(Elementary.Cos(z.c));
            }
            return new DoubleComplex(Elementary.Cos(z.c) * Math.Cosh(z.d), -Elementary.Sin(z.c) * Math.Sinh(z.d));
        }

        public static DoubleComplex Tan(DoubleComplex z)
        {
            if (z.IsReal)
            {
                return new DoubleComplex(Math.Tan(z.c));
            }
            if (Math.Abs(z.d) < 1.0)
            {
                double num = Elementary.Pow(Elementary.Cos(z.c), 2) + Elementary.Pow(Math.Sinh(z.d), 2);
                return new DoubleComplex((0.5 * Elementary.Sin(2.0 * z.c)) / num, (0.5 * Math.Sinh(2.0 * z.d)) / num);
            }
            double num2 = Math.Exp(-z.d);
            double num3 = (2.0 * num2) / (1.0 - (num2 * num2));
            double num4 = 1.0 + ((Elementary.Pow(Elementary.Cos(z.c), 2) * num3) * num3);
            double num5 = num3 * num3;
            double num6 = 1.0 / Math.Tanh(z.d);
            return new DoubleComplex(((0.5 * Math.Sin(2.0 * z.c)) * num5) / num4, num6 / num4);
        }

        public static DoubleComplex Asin(double a)
        {
            if (Math.Abs(a) <= 1.0)
            {
                return new DoubleComplex(Math.Asin(a));
            }
            if (a > 0.0)
            {
                return new DoubleComplex(1.5707963267948966, -Elementary.Acosh(a));
            }
            return new DoubleComplex(-1.5707963267948966, Elementary.Acosh(-a));
        }

        public static DoubleComplex Asin(DoubleComplex z)
        {
            double num;
            double num2;
            if (z.d == 0.0)
            {
                if (Math.Abs(z.c) <= 1.0)
                {
                    return new DoubleComplex(Math.Asin(z.c));
                }
                return Asin(z.c);
            }
            double num3 = Math.Abs(z.c);
            double b = Math.Abs(z.d);
            double num5 = Elementary.Hypot(num3 + 1.0, b);
            double num6 = Elementary.Hypot(num3 - 1.0, b);
            double num7 = 0.5 * (num5 + num6);
            double d = num3 / num7;
            double num9 = b * b;
            if (d <= 0.6417)
            {
                num = Math.Asin(d);
            }
            else if (num3 <= 1.0)
            {
                double num10 = (0.5 * (num7 + num3)) * ((num9 / ((num5 + num3) + 1.0)) + (num6 + (1.0 - num3)));
                num = Math.Atan(num3 / Math.Sqrt(num10));
            }
            else
            {
                double num11 = num7 + num3;
                double num12 = 0.5 * ((num11 / ((num5 + num3) + 1.0)) + (num11 / (num6 + (num3 - 1.0))));
                num = Math.Atan(num3 / (b * Math.Sqrt(num12)));
            }
            if (num7 > 1.5)
            {
                num2 = Math.Log(num7 + Math.Sqrt((num7 * num7) - 1.0));
            }
            else
            {
                double num13;
                if (num3 < 1.0)
                {
                    num13 = 0.5 * ((num9 / (num5 + (num3 + 1.0))) + (num9 / (num6 + (1.0 - num3))));
                }
                else
                {
                    num13 = 0.5 * ((num9 / (num5 + (num3 + 1.0))) + (num6 + (num3 - 1.0)));
                }
                num2 = Elementary.Log1PlusX(num13 + Math.Sqrt(num13 * (num7 + 1.0)));
            }
            return new DoubleComplex((z.c >= 0.0) ? num : -num, (z.d >= 0.0) ? num2 : -num2);
        }

        public static DoubleComplex Acos(double a)
        {
            if (Math.Abs(a) <= 1.0)
            {
                return new DoubleComplex(Math.Acos(a));
            }
            if (a < 0.0)
            {
                return new DoubleComplex(3.1415926535897931, -Elementary.Acosh(-a));
            }
            return new DoubleComplex(0.0, Elementary.Acosh(a));
        }

        public static DoubleComplex Acos(DoubleComplex z)
        {
            double num8;
            double num9;
            if (z.d == 0.0)
            {
                return Acos(z.c);
            }
            double num = Math.Abs(z.c);
            double b = Math.Abs(z.d);
            double num3 = Elementary.Hypot(num + 1.0, b);
            double num4 = Elementary.Hypot(num - 1.0, b);
            double num5 = 0.5 * (num3 + num4);
            double d = num / num5;
            double num7 = b * b;
            if (d <= 0.6417)
            {
                num8 = Math.Acos(d);
            }
            else if (num <= 1.0)
            {
                double num10 = (0.5 * (num5 + num)) * ((num7 / ((num3 + num) + 1.0)) + (num4 + (1.0 - num)));
                num8 = Math.Atan(Math.Sqrt(num10) / num);
            }
            else
            {
                double num11 = num5 + num;
                double num12 = 0.5 * ((num11 / ((num3 + num) + 1.0)) + (num11 / (num4 + (num - 1.0))));
                num8 = Math.Atan((b * Math.Sqrt(num12)) / num);
            }
            if (num5 > 1.5)
            {
                num9 = Math.Log(num5 + Math.Sqrt((num5 * num5) - 1.0));
            }
            else
            {
                double num13;
                if (num < 1.0)
                {
                    num13 = 0.5 * ((num7 / (num3 + (num + 1.0))) + (num7 / (num4 + (1.0 - num))));
                }
                else
                {
                    num13 = 0.5 * ((num7 / (num3 + (num + 1.0))) + (num4 + (num - 1.0)));
                }
                num9 = Elementary.Log1PlusX(num13 + Math.Sqrt(num13 * (num5 + 1.0)));
            }
            return new DoubleComplex((z.c >= 0.0) ? num8 : (3.1415926535897931 - num8), (z.d >= 0.0) ? -num9 : num9);
        }

        public static DoubleComplex Atan(DoubleComplex z)
        {
            double num3;
            if (z.d == 0.0)
            {
                return new DoubleComplex(Math.Atan(z.c));
            }
            double modulus = z.Modulus;
            double num2 = (2.0 * z.d) / (1.0 + (modulus * modulus));
            if (Math.Abs(num2) < 0.1)
            {
                num3 = 0.25 * (Elementary.Log1PlusX(num2) - Elementary.Log1PlusX(-num2));
            }
            else
            {
                double num4 = Elementary.Hypot(z.c, z.d + 1.0);
                double num5 = Elementary.Hypot(z.c, z.d - 1.0);
                num3 = 0.5 * Math.Log(num4 / num5);
            }
            if (z.c != 0.0)
            {
                return new DoubleComplex(0.5 * Math.Atan2(2.0 * z.c, (1.0 + modulus) * (1.0 - modulus)), num3);
            }
            if (Math.Abs(z.d) <= 1.0)
            {
                return new DoubleComplex(0.0, num3);
            }
            if (z.d < 0.0)
            {
                return new DoubleComplex(-1.5707963267948966, num3);
            }
            return new DoubleComplex(1.5707963267948966, num3);
        }

        public static DoubleComplex Sinh(DoubleComplex z)
        {
            if (z.IsReal)
            {
                return new DoubleComplex(Math.Sinh(z.c));
            }
            return new DoubleComplex(Math.Sinh(z.c) * Elementary.Cos(z.d), Math.Cosh(z.c) * Elementary.Sin(z.d));
        }

        public static DoubleComplex Cosh(DoubleComplex z)
        {
            if (z.IsReal)
            {
                return new DoubleComplex(Math.Cosh(z.c));
            }
            return new DoubleComplex(Math.Cosh(z.c) * Elementary.Cos(z.d), Math.Sinh(z.c) * Elementary.Sin(z.d));
        }

        public static DoubleComplex Tanh(DoubleComplex z)
        {
            return (Sinh(z) / Cosh(z));
        }

        public static DoubleComplex Asinh(DoubleComplex z)
        {
            DoubleComplex complex = new DoubleComplex(-z.d, z.c);
            DoubleComplex complex2 = Asin(complex);
            return new DoubleComplex(complex2.d, -complex2.c);
        }

        public static DoubleComplex Acosh(DoubleComplex z)
        {
            DoubleComplex complex = Acos(z);
            if (complex.d > 0.0)
            {
                return new DoubleComplex(complex.d, -complex.c);
            }
            return new DoubleComplex(-complex.d, complex.c);
        }

        public static DoubleComplex Atanh(DoubleComplex z)
        {
            DoubleComplex complex = new DoubleComplex(-z.d, z.c);
            DoubleComplex complex2 = Atan(complex);
            return new DoubleComplex(complex2.d, -complex2.c);
        }

        public static double[] GetRealPart(DoubleComplex[] sourceArray)
        {
            if (object.ReferenceEquals(sourceArray, null))
            {
                throw new ArgumentNullException("sourceArray");
            }
            double[] numArray = new double[sourceArray.Length];
            for (int i = 0; i < sourceArray.Length; i++)
            {
                numArray[i] = sourceArray[i].c;
            }
            return numArray;
        }

        public static double[] GetImaginaryPart(DoubleComplex[] sourceArray)
        {
            if (object.ReferenceEquals(sourceArray, null))
            {
                throw new ArgumentNullException("sourceArray");
            }   
            double[] numArray = new double[sourceArray.Length];
            for (int i = 0; i < sourceArray.Length; i++)
            {
                numArray[i] = sourceArray[i].d;
            }
            return numArray;
        }

    

   
        static DoubleComplex()
        {
            I = new DoubleComplex(0.0, 1.0);
            Zero = new DoubleComplex(0.0, 0.0);
            One = new DoubleComplex(1.0, 0.0);
            NaN = new DoubleComplex(double.NaN, double.NaN);
            Infinity = new DoubleComplex(double.PositiveInfinity, double.PositiveInfinity);
        }





        #endregion




    }
}
